﻿using System;
using System.Device.Location;
using Microsoft.Xna.Framework;
using AugmentedReality;

namespace AugmentedReality
{
    /// <summary>
    /// Klasa dostarczająca metod konwersji pomiędzy jednostkami kątów, metod zamiany wektorów ze współrzędnych biegunowych na kartezjańskie,
    /// oraz metod wyliczania azymutu.
    /// </summary>
    public class Conversion
    {

        /// <summary>
        /// Zamienia wektor w płaszczyźnie XZ ze współrzędnych biegunowych do kartezjańskich.
        /// </summary>
        /// <param name="degree">Kąt w stopniach.</param>
        /// <param name="radius">Promień wektora.</param>
        /// <returns>Wektor w płaszczyźnie XZ we współrzędnych kartezjańskich.</returns>
        public static Vector3 PolarXZToVector(double degree, double radius)
        {
            double radian = Conversion.DegreeToRadian(degree - 90.0);
            float x = (float)Math.Round(radius * Math.Cos(radian));
            float z = (float)Math.Round(radius * Math.Sin(radian));
            return new Vector3(x, 0, z);
        }

        /// <summary>
        /// Przelicza radiany na stopnie.
        /// </summary>
        /// <param name="radian">Kąt w radianach</param>
        /// <returns>Kąt w stoponiach</returns>
        public static double RadianToDegree(double radian)
        {
            return radian * 180.0 / Math.PI;
        }

        /// <summary>
        /// Przelicza stopnie na radiany.
        /// </summary>
        /// <param name="degree">Kąt w stopniach.</param>
        /// <returns>Kąt w radianach.</returns>
        public static double DegreeToRadian(double degree)
        {
            return degree * Math.PI / 180;
        }

        /// <summary>
        /// Wylicza 'azymut' dla dwóch punktów określonych długością i szerokością geograficzną.
        /// </summary>
        /// <param name="latitudeStart">Szerokość geograficzna pierwszego punktu</param>
        /// <param name="longitudeStart">Długość geograficzna pierwszego punktu</param>
        /// <param name="latitudeEnd">Szerokość geograficzna punktu docelowego</param>
        /// <param name="longitudeEnd">Długość geograficzna docelowego punktu</param>
        /// <param name="unit">Jednostka kąta, w której ma być zwrócony wynik</param>
        /// <returns>'Azymut' dla dwóch punktów</returns>
        public static double CalculateBearing(double latitudeStart, double longitudeStart, double latitudeEnd, double longitudeEnd, AngleUnits unit)
        {
            double radian1 = Conversion.DegreeToRadian(longitudeEnd - longitudeStart);
            double num1 = Conversion.DegreeToRadian(latitudeStart);
            double radian2 = Conversion.DegreeToRadian(latitudeEnd);
            double num2 = Math.Atan2(Math.Sin(radian1) * Math.Cos(radian2), Math.Cos(num1) * Math.Sin(radian2) - Math.Sin(num1) * Math.Cos(radian2) * Math.Cos(radian1));
            if (unit == AngleUnits.Radians)
            {
                return num2 + Conversion.DegreeToRadian(180.0);
            }
            return Conversion.RadianToDegree(num2) + 180.0;
        }

        /// <summary>
        /// Wylicza 'azymut' dla dwóch punktów określonych wartosciami typu <c>GeoCoordinate</c>.
        /// </summary>
        /// <param name="coordinateSource">Współrzędne pierwszego punktu</param>
        /// <param name="coordinateDest">Współrzędne punktu docelowego</param>
        /// <param name="unit">Jednostka kąta, w której ma być zwrócony wynik</param>
        /// <returns>'Azymut' dla dwóch punktów określonych wartosciami typu <c>GeoCoordinate</c></returns>
        public static double CalculateBearing(GeoCoordinate coordinateSource, GeoCoordinate coordinateDest, AngleUnits unit)
        {
            return Conversion.CalculateBearing(coordinateSource.Latitude, coordinateSource.Longitude, coordinateDest.Latitude, coordinateDest.Longitude, unit);
        }
    }
}
